package com.zhangmeng.tools.editors.monaco;

import com.zhangmeng.tools.utils.AlertUtils;
import com.zhangmeng.tools.utils.ClipboardUtils;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import lombok.extern.slf4j.Slf4j;
import netscape.javascript.JSObject;

/**
 * editor.action.addCommentLine：添加行注释（Toggle Line Comment）
 * editor.action.addCursorsToBottom：在文件尾部添加光标（Add Cursors To Bottom）
 * editor.action.addCursorsToTop：在文件开头添加光标（Add Cursors To Top）
 * editor.action.addSelectionToNextFindMatch：选取当前匹配后的下一个匹配项（Add Selection To Next Find Match）
 * editor.action.addSelectionToPreviousFindMatch：选取当前匹配前的上一个匹配项（Add Selection To Previous Find Match）
 * editor.action.centerLineInViewport：将当前行垂直居中（Center Line In Viewport）
 * editor.action.clipboardCopyAction：复制当前选中内容到剪切板（Copy）
 * editor.action.clipboardCutAction：剪切当前选中内容到剪切板（Cut）
 * editor.action.clipboardPasteAction：从剪切板中粘贴内容（Paste）
 * editor.action.commentLine：对选中文本添加或取消行注释（Toggle Line Comment）
 * editor.action.copyLinesDownAction：复制当前行并粘贴到下一行（Copy Lines Down）
 * editor.action.copyLinesUpAction：复制当前行并粘贴到上一行（Copy Lines Up）
 * editor.action.createCursorUndo：撤销所有光标修改（Undo Cursor）
 * editor.action.cursorColumnSelectDown：向下纵向区域选择行（Cursor Column Select Down）
 * editor.action.cursorColumnSelectLeft：向左纵向区域选择该行字符（Cursor Column Select Left）
 * editor.action.cursorColumnSelectPageDown：向下以页面为单位进行纵向区域选择（Cursor Column Select Page Down）
 * editor.action.cursorColumnSelectPageUp：向上以页面为单位进行纵向区域选择（Cursor Column Select Page Up）
 * editor.action.cursorColumnSelectRight：向右纵向区域选择该行字符（Cursor Column Select Right）
 * editor.action.cursorColumnSelectUp：向上纵向区域选择行（Cursor Column Select Up）
 * editor.action.cursorDown：将光标向下移动（Cursor Down）
 * editor.action.cursorEnd：将光标定位到行末尾（Cursor End）
 * editor.action.cursorHalfPageDown：向下移动半个页面距离（Cursor Half Page Down）
 * editor.action.cursorHalfPageUp：向上移动半个页面距离（Cursor Half Page Up）
 * editor.action.cursorHome：将光标定位到行首（Cursor Home）
 * editor.action.cursorLeft：将光标向左移动（Cursor Left）
 * editor.action.cursorPageDown：向下翻页（Cursor Page Down）
 * editor.action.cursorPageUp：向上翻页（Cursor Page Up）
 * editor.action.cursorRight：将光标向右移动（Cursor Right）
 * editor.action.cursorTop：将光标定位到文件开头（Cursor Top）
 * editor.action.cursorUp：将光标向上移动（Cursor Up）
 * editor.action.deleteLines：删除当前行或选中的多行（Delete Lines）
 * editor.action.deleteAllLeft：删除光标到行首的所有内容（Delete All Left）
 * editor.action.deleteAllRight：删除光标到行尾的所有内容（Delete All Right）
 * editor.action.deleteLeft：删除光标前的字符（Delete Left）
 * editor.action.deleteRight：删除光标后的字符（Delete Right）
 * editor.action.duplicateSelection：复制并插入一份当前选中内容（Duplicate Selection）
 * editor.action.editor.action.insertSnippet：插入代码片段（Insert Snippet）
 * editor.action.filterActions：将行为过滤器或快捷键过滤器应用于列表（Filter Actions）
 * editor.action.goToDeclaration：跳转到变量声明处（Go to Declaration）
 * editor.action.goToImplementation：跳转到变量实现处（Go to Implementation）
 * editor.action.goToTypeDefinition：查找类型定义（Go to Type Definition）
 * editor.action.insertCursorAbove：插入一个向上的光标（Insert Cursor Above）
 * editor.action.insertCursorAtEndOfEachLineSelected：插入在每行末尾的光标(Insert Cursor at End of Each Line Selected)
 * editor.action.insertCursorBelow：插入一个向下的光标（Insert Cursor Below）
 * editor.action.insertLineAfter：在当前行下面插入一行（Insert Line After）
 * editor.action.insertLineBefore：在当前行上面插入一行（Insert Line Before）
 * editor.action.indentLines：将选中行缩进（Indent Lines）
 * editor.action.indentUsingSpaces：使用空格进行缩进（Indent Using Spaces）
 * editor.action.intersectSelections：保留所有光标的交集，取消其余光标（Intersect Selections）
 * editor.action.moveLinesDownAction：将选中的行向下移动一行（Move Lines Down）
 * editor.action.moveLinesUpAction：将选中的行向上移动一行（Move Lines Up）
 * editor.action.moveSelectionToNextFindMatch：将光标移到下一个匹配项处，并取消选择（Move Selection to Next Find Match）
 * editor.action.moveSelectionToPreviousFindMatch：将光标移到上一个匹配项处，并取消选择（Move Selection to Previous Find Match）
 * editor.action.moveToCenter：将光标定位到屏幕中央（Move To Center）
 * editor.action.navigateToNextError：跳转到下一个错误（Go to Next Error）
 * editor.action.navigateToPreviousError：跳转到上一个错误（Go to Previous Error）
 * editor.action.newLineAbove：在当前行上方新建一行（New Line Above）
 * editor.action.newLineBelow：在当前行下方新建一行（New Line Below）
 * editor.action.nextMatchFindAction：查找下一个匹配项（Next Match Find）
 * editor.action.outdentLines：将选中行的缩进减少（Outdent Lines）
 * editor.action.outdentUsingSpaces：使用空格减少缩进（Outdent Using Spaces）
 * editor.action.pasteSelection：粘贴文本并替换当前选中内容（Paste Selection）
 * editor.action.quickFix：快速修复错误（Quick Fix）
 * editor.action.quickOutline：打开当前文件的大纲视图（Quick Outline）
 * editor.action.redo：重做最近一次取消操作（Redo）
 * editor.action.referenceSearch.trigger：查找该变量的所有引用（Find All References）
 * editor.action.removeCommentLine：移除行注释（Toggle Line Comment）
 * editor.action.replaceAll：在全局范围内查找并替换所有匹配项；（Replace All）；通常使用 Command+Shift+H 快捷键
 */
@Slf4j
public class MonacoWebView extends AnchorPane {

    public SimpleStringProperty text_code = new SimpleStringProperty("");

    public void setText(String text){
        log.info("text:" + text);
        text_code.setValue(text);
    }

    private JSObject window;

    public MonacoWebView() {
        init();
    }

    private File file;

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public WebView getView() {
        return view;
    }

    public void setView(WebView view) {
        this.view = view;
    }

    private WebView view = new WebView();

    public void init() {

        WebEngine engine = view.getEngine();

        String url = this.getClass().getResource("/static/editors/index2.html").toExternalForm();

        engine.getLoadWorker().stateProperty().addListener(
                (ObservableValue<? extends Worker.State> ov, Worker.State oldState, Worker.State newState) -> {
                    if (newState == Worker.State.SUCCEEDED) {
                        window = (JSObject) engine.executeScript("window");
                        window.setMember("text_code",text_code);
                    }
                }
        );

        engine.load(url);
        AnchorPane.setTopAnchor(view, 0.0);
        AnchorPane.setBottomAnchor(view, 0.0);
        AnchorPane.setLeftAnchor(view, 0.0);
        AnchorPane.setRightAnchor(view, 0.0);
        getChildren().add(view);

        view.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
            log.info("event.getCode:" + event.getCode());
            if (event.isControlDown() && event.getCode() == KeyCode.C) {
                event.consume();
                JSObject editor = (JSObject) engine.executeScript("window");
                //获取所选文本
                String text= editor.call("getSelected").toString();
                ClipboardUtils.setString(text);
            }
            if (event.isControlDown() && event.getCode() == KeyCode.X) {
                event.consume();
                JSObject editor = (JSObject) engine.executeScript("window");
                //获取所选文本
                String text= editor.call("getSelected").toString();
                ClipboardUtils.setString(text);
                //删除所选文本
                editor.call("removeSelectText"); // 删除选中的内容
            }


            if (event.isControlDown() && event.getCode() == KeyCode.S) {//保存
                event.consume();
                if (file != null){
                    try {
                        FileWriter writer = new FileWriter(file);
                        writer.write(text_code.getValue());
                        writer.flush();
                        writer.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }else {
                    //
                }
                AlertUtils.alert_warning("保存成功!");
            }

            if (event.isControlDown() && event.getCode() == KeyCode.DIVIDE) {//注释
                event.consume();
                window.call("commentLine");
            }

            if (event.isControlDown() && event.getCode() == KeyCode.O) {
                event.consume();
                //打开文件
                Stage stage = new Stage();
                FileChooser dc = new FileChooser();
                dc.setTitle("文件选择");
                dc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文件类型", "*.java", "*.go", "*.txt", "*.json", "*.sql"));
                File file = dc.showOpenDialog(stage);
                String file_content = null;
                try {
                    file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8);
                } catch (IOException e) {
                    try {
                        file_content = Files.readString(file.toPath(), Charset.forName("GBK"));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
                this.file = file;
                JSObject editor = (JSObject) engine.executeScript("window");
                editor.call("setValue",file_content);
            }

        });
    }

    public static String getText() {
        return """
                package com.zhangmeng.tools.editors.monaco;
                                
                import com.zhangmeng.tools.utils.AlertUtils;
                import javafx.scene.input.KeyCode;
                import javafx.scene.input.KeyEvent;
                import javafx.scene.layout.AnchorPane;
                import javafx.scene.web.WebEngine;
                import javafx.scene.web.WebView;
                import javafx.stage.FileChooser;
                import javafx.stage.Stage;
                                
                import java.io.File;
                import java.io.FileWriter;
                import java.io.IOException;
                import java.nio.charset.Charset;
                import java.nio.charset.StandardCharsets;
                import java.nio.file.Files;
                                
                public class MonacoWebView extends AnchorPane {
                   \s
                    private File file;
                                
                    private WebView view = new WebView();
                                
                    public void init(){
                 \s
                        WebEngine engine = view.getEngine();
                                
                        String url = this.getClass().getResource("/static/editors/index2.html").toExternalForm();
                        engine.load(url);
                        AnchorPane.setTopAnchor(view,0.0);
                        AnchorPane.setBottomAnchor(view,0.0);
                        AnchorPane.setLeftAnchor(view,0.0);
                        AnchorPane.setRightAnchor(view,0.0);
                        getChildren().add(view);
                                
                        view.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
                            if (event.isControlDown() && event.getCode() == KeyCode.S){//保存
                                event.consume();
                                AlertUtils.alert_warning("保存成功!");
                            }
                                
                            if (event.isControlDown() && event.getCode() == KeyCode.O){
                                event.consume();
                                //打开文件
                                Stage stage = new Stage();
                                FileChooser dc = new FileChooser();
                                dc.setTitle("文件选择");
                                dc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文件类型", "*.java", "*.go", "*.txt", "*.json", "*.sql"));
                                File file = dc.showOpenDialog(stage);
                                String file_content = null;
                                try {
                                    file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8);
                                } catch (IOException e) {
                                    try {
                                        file_content = Files.readString(file.toPath(), Charset.forName("GBK"));
                                    } catch (IOException ex) {
                                        ex.printStackTrace();
                                    }
                                }
                                this.file = file;
                                engine.executeScript("setValue('" + getText() +"')");
                            }
                                
                        });
                    }
                   \s
                    public static String getText(){
                        return ""\"
                                ""\";
                    }
                }
                                
                """;
    }
}
